#include <stdint.h>
#include "main.h"
#include "hal_exp_valve.h"
#include "Timer.h"

#define FREQ_MIN_VALUE    10
#define FREQ_MAX_VALUE    100

#define EXV_INIT_VALUE		560

/* Macro Define */
#define FREQ_MIN_VALUE    10
#define FREQ_MAX_VALUE    100
#define PULSE_NUM         8
#define INITIAL_OPEN      0
#define INITIAL_CLOSE     1
/*
opening <-
a  11000001
b  01110000
-a 00011100
-b 00000111

closing <-
a  10000011
b  00001110
-a 00111000
-b 11100000
*/

typedef struct
{
    u8 PhaseA;
    u8 PhaseB;
    u8 PhaseAN;
    u8 PhaseBN;
} ValvePhase;

const ValvePhase Phase[PULSE_NUM] =
{
  {1,0,0,0},
  {1,1,0,0},
  {0,1,0,0},
  {0,1,1,0},  
  {0,0,1,0},
  {0,0,1,1},
  {0,0,0,1},
  {1,0,0,1},       
};

VALVE ElectricValve;
s16 NewAbsStep;
/****************Include  Section  End*****************************************************/
/****************Static define  Section  Begin***************************************************/


//static u16 LastCloseValveTimer;
/****************Static Variation Definition Section End******************************************/
/****************Global Variation Definition Section End******************************************/



/****************Global Variation Definition Section End******************************************/
/****************Function Prototype Declaration Section Begin*************************************/

void ValveInitial(void);
void ValveInitClose(void);
u8 Valve_Control(void);
void AdjustValve(s16 Step);
void SetRelayState(u8 Relay, u8 State);
void ValveSetFreq (u8 freq);
u8 ValveGetFreq (void);
void ValveSetAdjustPercent(u16 percent);
s16 ValveGetAdjustPercent(void);
u8 ValveGetStepPercent(void);


void ResetPulseAandB(void);
void ExcitePulseAandB(void);
/****************Function Prototype Declaration Section End*************************************/
/****************Function Prototype Declaration Section Begin*************************************/
void ValveInitial()
{
  ResetPulseAandB();
	ElectricValve.Operate = VALVEIDLE;
	ElectricValve.SetFreq = 20;
	ElectricValve.Pulse = 255;
	ElectricValve.Adjust = 0;
	ElectricValve.InitialState = INITIAL_CLOSE;
	if(INITIAL_OPEN == ElectricValve.InitialState)
	{
		ElectricValve.Step = 0;
		AdjustValve(EXV_INIT_VALUE);
	}
	else
	{
    ElectricValve.Step = EXV_INIT_VALUE;
		AdjustValve(0-EXV_INIT_VALUE);
	}	
}

/*
 * Function Name:   ValveInitClose
 * Description:
 * Return Value: void
 * Parameter:   void
 * Note:     
 */
void ValveInitClose(void)
{
   AdjustValve(0-EXV_INIT_VALUE);
}
/*
 * Function Name:   Valve_Control
 * Description:
 * Return Value: void
 * Parameter:   void
 */
u8 Valve_Control(void)
{
	u16 TicksNow, TicksElapsed;
	
	TicksNow = Timer2_Get32Ticks();
	TicksElapsed = TicksNow - ElectricValve.Update;
	if(TicksElapsed < ElectricValve.Freq)
	{
		return 0;
	}
	ElectricValve.Update = Timer2_Get32Ticks();
	
	switch(ElectricValve.Operate)
	{
		case VALVEOPENSTART:
			ElectricValve.Freq = 500;
			ElectricValve.Operate = VALVEOPENING;
			if(ElectricValve.Adjust==0)
			{
				ElectricValve.Operate=VALVESTOP;
				ElectricValve.Freq = 500;
				break;
			}

			if(ElectricValve.Step == 500)///
			{
				ElectricValve.Operate=VALVESTOP;
				ElectricValve.Adjust=0;
				break;
			}
			if((ElectricValve.Pulse == 255)||(ElectricValve.Pulse == 7))
			{
				ElectricValve.Pulse = 0;
			}
		break;
	case VALVEOPENING :
		if(ElectricValve.Adjust==0)
		{
			//ElectricValve.Step-=1;
			ElectricValve.Operate=VALVESTOP;
			if((ElectricValve.Pulse == 255)||(ElectricValve.Pulse == (PULSE_NUM-1)))
			{
				ElectricValve.Pulse = 0;
			}
			else
			{
				ElectricValve.Pulse++ ;
			}
			ExcitePulseAandB();
			ElectricValve.Freq = 500;
			if(ElectricValve.Step == EXV_INIT_VALUE)
			{
				ElectricValve.Step = 500;
			}
			break;
		}
		#if 0                        
		if(ElectricValve.Step == EXV_INIT_VALUE)///
		{
			ElectricValve.Operate=VALVESTOP;
			ElectricValve.Adjust=0;
			ElectricValve.Freq = 500;
			break;
		}

		#endif            
		if((ElectricValve.Pulse == 255)||(ElectricValve.Pulse == (PULSE_NUM-1)))
		{
			ElectricValve.Pulse = 0;
		}
		else
		{
			ElectricValve.Pulse++ ;
		}
		ExcitePulseAandB();
		ElectricValve.Adjust --;
		ElectricValve.Step ++;
		ElectricValve.Freq = ElectricValve.SetFreq;
		break;
	case VALVECLOSESTART:
		ElectricValve.Freq = 500;
		ElectricValve.Operate = VALVECLOSEING;
		if(ElectricValve.Adjust==0)
		{
			ElectricValve.Operate = VALVESTOP;
			ElectricValve.Freq = 500;
			break;
		}
		if((ElectricValve.Pulse == 255)||(ElectricValve.Pulse == 0))
		{
			ElectricValve.Pulse = (PULSE_NUM-1);
		}
		break;
	case VALVECLOSEING:
		if(ElectricValve.Adjust==0)
		{
			ElectricValve.Operate = VALVESTOP;
			if(ElectricValve.Pulse == 0)
			{
				ElectricValve.Pulse = (PULSE_NUM-1);
			}
			else
			{
				ElectricValve.Pulse-- ;
			}
			ExcitePulseAandB();
			if(ElectricValve.Step ==0)
			{
				for(int i=0; i<8; i++)
				{
					if(ElectricValve.Pulse == 0)
					{
						ElectricValve.Pulse = (PULSE_NUM-1);
					}
					else
					{
						ElectricValve.Pulse-- ;
					}
					ExcitePulseAandB();
				}
			}
			ElectricValve.Freq = 500;
			break;
		}
		if(ElectricValve.Pulse == 0)
		{
			ElectricValve.Pulse = (PULSE_NUM-1);
		}
		else
		{
			ElectricValve.Pulse-- ;
		}
		ExcitePulseAandB();
		ElectricValve.Adjust++;
		ElectricValve.Step --;
		ElectricValve.Freq = ElectricValve.SetFreq;
		break;
	case VALVESTOP:
		ElectricValve.Freq = 1;
		ElectricValve.Operate = VALVEIDLE;
		ResetPulseAandB();
		break;
	case VALVEIDLE:
		ElectricValve.Freq =ElectricValve.SetFreq;
		if(ElectricValve.Step != NewAbsStep)
		{
			AdjustValveAbs(NewAbsStep);
		}
		break;
	case VALVECLOSEPAUSE:
		ResetPulseAandB();
		ElectricValve.Freq = 1;
		break;
	case VALVEOPENPAUSE:
		ResetPulseAandB();
		ElectricValve.Freq = 1;
		break;
	}
	return 1;
}
/*
 * Function Name:   ExcitePulseAandB
 * Description:
 * Return Value: void
 * Parameter:   void
 * Note:
 */
void  ExcitePulseAandB(void)
{
    PULSEA=Phase[ElectricValve.Pulse].PhaseA;
    PULSEB=Phase[ElectricValve.Pulse].PhaseB;
    PULSENA=Phase[ElectricValve.Pulse].PhaseAN;
    PULSENB=Phase[ElectricValve.Pulse].PhaseBN; 
}


/*
 * Function Name:   ResetPulseAandB
 * Description:  ��A��B��ȫ����0
 * Return Value: void
 * Parameter:   void
 * Note:
 */
void ResetPulseAandB(void)
{
     PULSEA=0;
     PULSEB=0;
     PULSENA=0;
     PULSENB=0;
}
/*
 * Function Name:   AdjustValve
 * Description:  �����������ͷ�����
 * Return Value: void
 * Parameter:   s16 Step
 * Note:
 */
void AdjustValve(s16 Step)
{
    /*
     Step > 0 open valve
     Step < 0 close valve
*/
    ElectricValve.Adjust+=Step;
    if(ElectricValve.Adjust < 0) //��Ҫ���е���Close����
    {
			switch(ElectricValve.Operate)
			{
				case VALVEIDLE:
						ElectricValve.Operate=VALVECLOSESTART;
						break;
				case VALVECLOSEPAUSE:
				case VALVECLOSEING:
				case VALVECLOSESTART:
						break;
				case VALVEOPENPAUSE:
						ElectricValve.Operate=VALVECLOSESTART;
						break;
				case VALVEOPENING:
						ElectricValve.Operate=VALVECLOSESTART;
						break;
				case VALVEOPENSTART:
						ElectricValve.Operate=VALVECLOSESTART;
						break;
				case VALVESTOP:
						//ElectricValve.Step = 0;
						break;
						
			}
    }
    else if(ElectricValve.Adjust > 0)
    {
			switch(ElectricValve.Operate)
			{
					case VALVEIDLE:
							ElectricValve.Operate=VALVEOPENSTART;
							break;
					case VALVEOPENPAUSE:
					case VALVEOPENING:
					case VALVEOPENSTART:
							break;
					case VALVECLOSEPAUSE:
							ElectricValve.Operate= VALVEOPENSTART;
							break;
					case VALVECLOSEING:
							ElectricValve.Operate= VALVEOPENSTART;
							break;
					case VALVECLOSESTART:
							ElectricValve.Operate= VALVEOPENSTART;
							break;
					case VALVESTOP:
							//ElectricValve.Step = 0;
							break;
							
			}
    }
    else
    {
        //ElectricValve.Step = 0;///nothing 0 is no Adjust
    
    }
}

void AdjustValveAbs(s16 AbsStep)
{
	s16 result;
	
	NewAbsStep = AbsStep;
	
	if(ElectricValve.Operate == VALVEIDLE)
	{
		result = (s16)AbsStep - (s16)ElectricValve.Step;
		ElectricValve.Adjust = result;
	}
	
	if(ElectricValve.Adjust < 0)
	{
		switch(ElectricValve.Operate)
		{
			case VALVEIDLE:
					ElectricValve.Operate=VALVECLOSESTART;
					break;
			case VALVECLOSEPAUSE:
			case VALVECLOSEING:
			case VALVECLOSESTART:
					break;
			case VALVEOPENPAUSE:
					ElectricValve.Operate=VALVECLOSESTART;
					break;
			case VALVEOPENING:
					if((ElectricValve.Pulse == 255)||(ElectricValve.Pulse == (PULSE_NUM-1)))
					{
						ElectricValve.Pulse = 0;
					}
					else
					{
						ElectricValve.Pulse++ ;
					}
					ExcitePulseAandB();
					ElectricValve.Freq = 500;
					if(ElectricValve.Step == EXV_INIT_VALUE)
					{
						ElectricValve.Step = 500;
					}
					ElectricValve.Operate=VALVECLOSESTART;
					break;
			case VALVEOPENSTART:
					ElectricValve.Operate=VALVECLOSESTART;
					break;
			case VALVESTOP:
					//if(AbsStep==0)AdjustValve(-1);
					break;
							
			}
	}
	else if(ElectricValve.Adjust > 0)
	{
		switch(ElectricValve.Operate)
		{
			case VALVEIDLE:
					ElectricValve.Operate=VALVEOPENSTART;
					break;
			case VALVEOPENPAUSE:
			case VALVEOPENING:
			case VALVEOPENSTART:
					break;
			case VALVECLOSEPAUSE:
					ElectricValve.Operate= VALVEOPENSTART;
					break;
			case VALVECLOSEING:		
					//ElectricValve.Step +=1;
					ElectricValve.Operate = VALVESTOP;
					if(ElectricValve.Pulse == 0)
					{
						ElectricValve.Pulse = (PULSE_NUM-1);
					}
					else
					{
						ElectricValve.Pulse-- ;
					}
					ExcitePulseAandB();
					ElectricValve.Freq = 500;
					ElectricValve.Operate= VALVEOPENSTART;
					break;
			case VALVECLOSESTART:
					ElectricValve.Operate= VALVEOPENSTART;
					break;
			case VALVESTOP:
					break;
						
		}
	}
	else
	{
			///nothing 0 is no Adjust
	
	}
}



/*
 * Function Name:   ValveGetSteps
 * Description:  ȡ�õ������ͷ�����
 * Return Value: u8 �������ͷ�����
 * Parameter:   void
 * Note:
 */
u16 ValveGetSteps(void)
{
    return ElectricValve.Step;
  
}

/*
 * Function Name:   ValveSetFreq
 * Description:  ���õ������ͷ�Ƶ��
 * Return Value: void
 * Parameter:   u8 �������ͷ�Ƶ��
 * Note:
 */
void ValveSetFreq (u8 freq)
{
	if((FREQ_MIN_VALUE <= freq) && (FREQ_MAX_VALUE >= freq))
	{
		ElectricValve.SetFreq =	freq;
	}
}

/*
 * Function Name:   ValveGetFreq
 * Description:  ȡ�õ������ͷ�Ƶ��
 * Return Value: u8 �������ͷ�Ƶ��
 * Parameter:   void
 * Note:
 */
u8 ValveGetFreq ()
{
	return ElectricValve.SetFreq;
}

/*
 * Function Name:   ValveGetSteps
 * Description:  ���õ������ͷ���ǰ����ռ�����岽���İٷֱ�
 * Return Value: u8 �������ͷ���ǰ����ռ�����岽���İٷֱ�
 * Parameter:   void
 * Note:
 */
void ValveSetAdjustPercent(u16 percent)
{
	u32 per = 500 * (u32)percent;
	s16 Adjust = (s16)(per / 1000);
	AdjustValveAbs(Adjust);
}

/*
 * Function Name:   ValveGetSteps
 * Description:  ȡ�õ������ͷ��������˵Ĳ����İٷֱ�
 * Return Value: u8 �������ͷ��������˵Ĳ����İٷֱ�
 * Parameter:   void
 * Note:
 */
s16 ValveGetAdjustPercent()
{
	return ElectricValve.Adjust / 5;
}

/*
 * Function Name:   ValveGetSteps
 * Description:  ȡ�õ������ͷ���ǰ����ռ�ܲ����İٷֱ�
 * Return Value: u8 �������ͷ���ǰ����ռ�ܲ����İٷֱ�
 * Parameter:   void
 * Note:
 */
u8 ValveGetStepPercent()
{
	return ElectricValve.Step / 5;
}


u16 ValveGetPercent()
{
	return ElectricValve.Step * 2;
}



